import type { AsyncReturnType } from 'type-fest';
import { globalPopups } from '~comp-b/global-popups';

interface AuthPopup {
  setPassword: typeof globalPopups.setPassword.open;
  updatePassword: typeof globalPopups.updatePassword.open;
  verifyEmail: typeof globalPopups.verifyEmail.open;
  enable2FA: typeof globalPopups.enable2FA.open;
  disable2FA: typeof globalPopups.disable2FA.open;
  verify2FA: typeof globalPopups.verify2FA.open;
}

type AuthPopupName = keyof AuthPopup;
type AuthPopupProps<N extends AuthPopupName> = Parameters<AuthPopup[N]>;
type AuthPopupReturn<N extends AuthPopupName> = ReturnType<AuthPopup[N]>;
type MyInfo = AsyncReturnType<typeof getMyInfo>;

type AuthPopupGuardReturn<T extends AuthPopupName = AuthPopupName> =
  | [T, ...AuthPopupProps<T>]
  | true
  | void;
type AuthPopupGuards = {
  [K in AuthPopupName]: (my: MyInfo) => AuthPopupGuardReturn;
};

const guards: AuthPopupGuards = {
  setPassword(my) {
    if (!my.email && !my.email_verified)
      return true;
    if (my.email && !my.email_verified)
      return ['verifyEmail', { email: my.email, type: 2 }];
  },
  updatePassword(my) {
    return my.email_verified ? true : ['setPassword'];
  },
  verifyEmail() {
    return true;
  },
  enable2FA(my) {
    if (!my.email_verified)
      return ['setPassword'];
    if (my.email_verified && !my.enable_authenticator)
      return true;
  },
  disable2FA(my) {
    if (my.enable_authenticator)
      return true;
  },
  verify2FA(my) {
    return my.enable_authenticator && my.email_verified ? true : ['enable2FA'];
  },
};

/**
 * 打开授权弹窗
 * @param name 弹窗名称
 * @param props 弹窗参数
 */
export async function openAuthFlowPopup<N extends AuthPopupName>(
  name: N,
  ...props: AuthPopupProps<N>
): Promise<AuthPopupReturn<N> | void> {
  const normalProps: any = typeof props[0] === 'object' ? props[0] : {};

  while (true) {
    globalPopups.loading.open();
    const my = await getMyInfo();
    globalPopups.loading.close();

    if (!my)
      return;

    const prePopup = getPrecondition(name, my, [name, props[0]]);

    if (!prePopup)
      return;

    const isTarget = Array.isArray(prePopup) && prePopup[0] === name;
    let popupPromise: Promise<any> | undefined;
    let popupRet: any;

    if (isTarget) {
      const props = normalProps;
      popupPromise = globalPopups[name].open(props);
    }
    else if (Array.isArray(prePopup)) {
      const props = (typeof prePopup[1] === 'object' ? prePopup[1] : {}) as any;
      popupPromise = globalPopups[prePopup[0]].open(props);
    }

    if (popupPromise instanceof Promise) {
      popupRet = await popupPromise;
    }

    if (isTarget)
      return popupRet;
  }
}

function getPrecondition(name: AuthPopupName, my: MyInfo, prevRes?: AuthPopupGuardReturn) {
  const res = guards[name](my);

  if (Array.isArray(res) && isAuthPopupName(res[0])) {
    return getPrecondition(res[0], my, res);
  }
  else if (res === true) {
    return prevRes;
  }
}

function isAuthPopupName(name: any): name is AuthPopupName {
  return String(name) in guards;
}

function getMyInfo() {
  const data = queryClient.fetchQuery({
    queryKey: [apis.apiUserInfo.id],
    queryFn: () => apis.apiUserInfo(undefined),
    staleTime: 1000 * 2,
  });

  return data;
}
